package top.rainbowecho.article.controller;

import com.fasterxml.jackson.annotation.JsonView;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.rainbowecho.article.service.IArticleService;
import top.rainbowecho.article.service.ICategoryService;
import top.rainbowecho.article.service.ILikeService;
import top.rainbowecho.article.service.ITagService;
import top.rainbowecho.article.vo.ArticleInfoVo;
import top.rainbowecho.article.vo.ArticleLikeVo;
import top.rainbowecho.article.vo.ArticleQueryVo;
import top.rainbowecho.article.vo.ArticleUploadVo;
import top.rainbowecho.common.exception.BlogException;
import top.rainbowecho.common.exception.WrongTokenTypeException;
import top.rainbowecho.common.util.*;
import top.rainbowecho.model.percona.Article;
import top.rainbowecho.model.percona.ArticleInfo;
import top.rainbowecho.model.percona.Category;
import top.rainbowecho.model.percona.Tag;
import top.rainbowecho.model.view.ArticleDetailView;
import top.rainbowecho.model.view.MicroArticleView;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * TODO 网站统计计算接口，使用切面对正常响应进行统一处理
 *
 * @author rainbow
 */
@RestController
@RequestMapping("/article")
@Slf4j
public class ArticleController {
    private IArticleService articleService;

    private ICategoryService categoryService;

    private ITagService tagService;

    private ILikeService likeService;

    @Autowired
    public void setLikeService(ILikeService likeService) {
        this.likeService = likeService;
    }

    @Autowired
    public void setTagService(ITagService tagService) {
        this.tagService = tagService;
    }

    @Autowired
    public void setCategoryService(ICategoryService categoryService) {
        this.categoryService = categoryService;
    }

    @Autowired
    public void setArticleService(IArticleService articleService) {
        this.articleService = articleService;
    }

    /**
     * 获取最近三篇的置顶文章
     *
     * @return 返回最近的三篇置顶文章
     */
    @GetMapping("/top")
    public ResponseEntity<Map<String, Object>> topThreeArticle() {
        List<Article> topThree = this.articleService.findTopThree();
        ImmutableMap<String, Object> result = ImmutableMap.of(ResultKey.DATA, topThree);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 根据操作类型，获取最热、最受欢迎、最多评论、最多阅读的三篇文章
     *
     * @param type 1为最热，2为最受欢迎，3为最多评论，4为最多阅读
     * @return 文章集合
     */
    @GetMapping("/top/user")
    public ResponseEntity<Map<String, Object>> typeTopThree(@RequestParam("type") int type) {
        List<ArticleInfo> topThree = this.articleService.findTypeTopThree(type);
        ImmutableMap<String, Object> result = ImmutableMap.of(ResultKey.DATA, topThree);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 置顶或取消置顶某篇文章
     *
     * @param articleId 文章id
     * @param isTop 1为置顶，0为取消置顶
     * @return 返回置顶结果
     */
    @PutMapping("/top/{articleId}")
    public ResponseEntity<Map<String, Object>> topArticle(@PathVariable("articleId") String articleId,@RequestParam("isTop") Integer isTop) {
        Article topArticle = new Article().setIsTop(isTop).setId(articleId);
        this.articleService.updateArticleTop(topArticle);
        ImmutableMap<String, Object> result = ImmutableMap.of(ResultKey.DATA, topArticle);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 分页获取文章列表
     *
     * @param page 分页参数，页数从0开始
     * @param categoryName 分类名
     * @param tagName 标签名
     * @param title 标题
     * @return microArticleView结构数据
     */
    @GetMapping
    @JsonView(MicroArticleView.class)
    public ResponseEntity<Map<String, Object>> queryArticleByPage(@PageableDefault Pageable page,
                                                        @RequestParam(name = "c", required = false) String categoryName,
                                                        @RequestParam(name = "t", required = false) String tagName,
                                                        @RequestParam(name = "s", required = false) String title) {
        ArticleQueryVo articleQueryVo = new ArticleQueryVo(categoryName, tagName, title);
        List<ArticleInfoVo> articleInfos = this.articleService.findArticles(articleQueryVo, page);
        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, articleInfos);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }

    /**
     * 用户为某篇文章点赞或取消点赞
     *
     * @param articleId 文章id
     * @param token 用户token
     * @param isLike 1为点赞操作，0为取消点赞操作
     * @return 提示信息
     */
    @PostMapping("/likeOperate/{articleId}")
    public ResponseEntity<Map<String, Object>> likeArticleOperate(@PathVariable("articleId") String articleId
            , @RequestHeader(CommonKey.OWN_AUTHORIZATION) String token, @RequestParam("isLike") Integer isLike) {
        try {
            String userId = CommonUtil.obtainInfoFromToken(token, JwtTokenKey.USER_ID);
            ArticleLikeVo likeVo = new ArticleLikeVo();
            likeVo.setArticleId(articleId);
            likeVo.setUserId(userId);

            String message;
            if (isLike == 1) {
                this.likeService.insertRecord(likeVo);
                message = ExceptionMessageContent.LIKE_SUCCESS;
            } else {
                int i = this.likeService.unlikeArticle(likeVo);
                message = i == 1 ? ExceptionMessageContent.UNLIKE_SUCCESS : ExceptionMessageContent.NO_LIKE;
            }

            ImmutableMap<String, Object> result = ImmutableMap.of(ResultKey.MESS, message);
            return new ResponseEntity<>(result, HttpStatus.OK);
        } catch (WrongTokenTypeException e) {
            throw new BlogException(e.getMessage());
        } catch (DuplicateKeyException e) {
            throw new BlogException(ExceptionMessageContent.HAS_LIKE);
        }

    }

    /**
     * 本地上传文章md文件
     *
     * @param uploadVo 文章上传对象
     * @return json响应
     * @throws IOException json序列化失败
     */
    @PostMapping("/upload")
    @Transactional(rollbackFor = {BlogException.class, IOException.class})
    public ResponseEntity<Map<String, Object>> uploadArticleFile(@Validated ArticleUploadVo uploadVo, BindingResult bindingResult) throws IOException {
        if (bindingResult.hasErrors()) {
            return CommonUtil.handleValidateError(bindingResult);
        }
        Article saveArticle = this.articleService.saveUploadArticle(uploadVo);

        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, saveArticle);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }

    /**
     * 获取某个文章的具体详情
     *
     * @param articleId 文章id
     * @return 某篇文章的信息
     */
    @GetMapping("/{id}")
    @JsonView(ArticleDetailView.class)
    public ResponseEntity<Map<String, Object>> articleDetail(@PathVariable("id") String articleId
            , @RequestHeader(required = false, value = CommonKey.OWN_AUTHORIZATION) String token) {
        try {
            String userId = CommonUtil.obtainInfoFromToken(token, JwtTokenKey.USER_ID);
            ArticleInfoVo articleInfo = this.articleService.readArticle(articleId, userId);

            ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, articleInfo);
            return new ResponseEntity<>(data, HttpStatus.OK);
        } catch (WrongTokenTypeException e) {
            throw new BlogException(e.getMessage());
        }
    }

    /**
     * 删除文章
     *
     * @param articleId 文章id
     */
    @DeleteMapping
    @Transactional(rollbackFor = BlogException.class)
    public void deleteArticle(@RequestParam("article") String articleId) {
        boolean deleteSuccess = this.articleService.removeById(articleId);
        if (!deleteSuccess) {
            log.error("删除文章失败");
            throw new BlogException(ExceptionMessageContent.DELETE_FAIL);
        }
    }

    /**
     * 添加分类
     *
     * @param category 分类数据
     * @return 添加成功的分类数据
     */
    @PostMapping("/category")
    @Transactional
    public ResponseEntity<Map<String, Object>> addCategory(Category category) {
        this.categoryService.saveCategory(category);

        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, category);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }

    /**
     * 获取所有目录
     *
     * @return 目录列表
     */
    @GetMapping("/category")
    @Transactional
    public ResponseEntity<Map<String, Object>> allCategory() {
        List<Category> categories = this.categoryService.findAllCategory();
        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, categories);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }

    /**
     * 获取所有标签
     *
     * @return 标签列表
     */
    @GetMapping("/tag")
    @Transactional
    public ResponseEntity<Map<String, Object>> allTag() {
        List<Tag> tags = this.tagService.getAllTag();
        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, tags);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }

    /**
     * 添加标签
     *
     * @param tag 标签数据
     * @return 添加成功的标签数据
     */
    @PostMapping("/tag")
    public ResponseEntity<Map<String, Object>> addTag(Tag tag) {
        this.tagService.saveTag(tag);

        ImmutableMap<String, Object> data = ImmutableMap.of(ResultKey.DATA, tag);
        return new ResponseEntity<>(data, HttpStatus.OK);
    }


}
